package com.jingdun.sport.task;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.xiaoymin.swaggerbootstrapui.util.CommonUtils;
import com.jingdun.sport.activity.SportRecords;
import com.jingdun.sport.bean.model.*;
import com.jingdun.sport.common.constants.RedisConstants;
import com.jingdun.sport.common.util.DateUtil;
import com.jingdun.sport.service.*;
import com.jingdun.sport.utils.CommentUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.unit.DataUnit;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Configuration      //1.主要用于标记配置类，兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
@Slf4j
public class SaticScheduleTask {

    @Autowired
    private RoomService roomService;

    @Autowired
    private RoomUserRelationService roomUserRelationService;

    @Autowired
    private RoomUserSportRecordPerDayService roomUserSportRecordPerDayService;

    @Autowired
    private SportActivityService sportActivityService;

    @Autowired
    private NewSportRecordsService newSportRecordsService;

    @Autowired
    private UserService userService;

    @Autowired
    private NewSOrderService newSOrderService;

    @Autowired
    private RoomService roomsService;

    @Autowired
    private SportConfigService sportConfigService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SyntheticPrizeService syntheticPrizeService;

    //每间隔5秒
    //@Scheduled(cron = "0/5 * * * * ?")


    //每天16:19:00
    //@Scheduled(cron = "0 19 16 * * ?")

    //每间隔2分钟, 10分钟
    //@Scheduled(cron = "0 0/2 * * * ?")
    //@Scheduled(cron = "0 0/10 * * * ?")

    //每天6:15:00
    //@Scheduled(cron = "0 45 6 * * ?")

    //每天23:00:00
    @Scheduled(cron = "0 1 0 * * ?")
    @PostConstruct
    private void configureTasks() {
        System.out.println("执行每日完成定时任务时间: " + LocalDateTime.now());
        //找到所有的活动室id的list, 结束日期是今天的
//        1、查询从今天之前所有已结束但未结算的活动
        Date today = new Date();
        System.out.println(today);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateNowStr = sdf.format(today);
        List<Room> unfinishedRoomList = roomService.getUnfinishedRoomList(dateNowStr);
        Set<Long> ufinishedRoomIdSet = unfinishedRoomList.stream().map(Room::getId).collect(Collectors.toSet());
//        获取所有房间对应用户的对应映射关系
//        List<RoomUserRelation> roomUserRelationList = roomUserRelationService.getAllRoomMapUserByRoomId(ufinishedRoomIdSet);
//        List<RoomUserSportRecordPerDay> roomUserSportRecordPerDayList = roomUserSportRecordPerDayService.getAllRoomMapUserByRoomId(ufinishedRoomIdSet);
//        2、遍历所有未结束的房间
        unfinishedRoomList.stream().forEach(unfinishedRoom -> {
//            全部都有运动的用户
            Set<String> allFinishedUserId = new HashSet<>();
//            每个活动下该用户对应的签到次数
            Map<String, Integer> userId2Count = new HashMap<>();
            Set<String> userIdSet = new HashSet<>();
            Map<String, Set<String>> userIdMapDate = new HashMap<>();
            Date date1 = DateUtil.parseDateyyyyMMdd(unfinishedRoom.getBeginDate());
            Date date2 = DateUtil.parseDateyyyyMMdd(unfinishedRoom.getEndDate());
            long betweenDay = DateUtil.daysBetween(date1, date2) + 1;

//            指定房间中所有用户
            Set<Long> unfinishedRoomUserRelationIdSet = new HashSet<>();
            unfinishedRoomUserRelationIdSet.add(unfinishedRoom.getId());
            List<RoomUserRelation> unfinishedRoomUserRelationSet = roomUserRelationService.getAllRoomMapUserByRoomId(unfinishedRoomUserRelationIdSet);
//            指定房间中所有用户运动记录
            List<RoomUserSportRecordPerDay> roomUserSportRecordPerDayList = roomUserSportRecordPerDayService.getAllRoomMapUserByRoomId(unfinishedRoomUserRelationIdSet);
            unfinishedRoomUserRelationSet.stream().forEach(unfinishedRoomUserRelation -> {
//                判断是否是该房间下的用户
                roomUserSportRecordPerDayList.stream().forEach(unfinishedRoomUserSportRecordPerDay -> {
//                        判断是否是该房间下的记录
                    if (unfinishedRoomUserSportRecordPerDay.getRoomId().equals(unfinishedRoom.getId())
                            && unfinishedRoomUserSportRecordPerDay.getUserId().equals(unfinishedRoomUserRelation.getUserId())) {
//                            过滤同一天同一用户重复提交运动记录
                        Set<String> createDate = userIdMapDate.get(unfinishedRoomUserRelation.getUserId());
                        if (createDate == null) {
                            userId2Count.put(unfinishedRoomUserRelation.getUserId(), new Integer(1));
                            Set<String> newCreateDate = new HashSet<>();
                            newCreateDate.add(unfinishedRoomUserSportRecordPerDay.getGmtCreate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                            userIdMapDate.put(unfinishedRoomUserRelation.getUserId(), newCreateDate);
                        } else {
                            if (!createDate.contains(unfinishedRoomUserSportRecordPerDay.getGmtCreate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                                Integer count = userId2Count.get(unfinishedRoomUserRelation.getUserId());
                                userId2Count.put(unfinishedRoomUserRelation.getUserId(), (count + 1));
                                Set<String> createDateSet = userIdMapDate.get(unfinishedRoomUserRelation.getUserId());
                                createDateSet.add(unfinishedRoomUserSportRecordPerDay.getGmtCreate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                            }
                        }
//                            判断是否有每天签到
                        if (userId2Count.get(unfinishedRoomUserSportRecordPerDay.getUserId()) == betweenDay) {
                            allFinishedUserId.add(unfinishedRoomUserSportRecordPerDay.getUserId());
                        }
                    }
                });
            });
//          给每天签到的人分配金额或更新房间状态，如果是押金则直接分完钱房间状态就变为2，宝箱全部未完成变为2，冒险全部完成变为2，其他情况房间状态为1
            if (!allFinishedUserId.isEmpty()) {
                double result;
                double perMoney = unfinishedRoom.getDeposit();
                LambdaQueryWrapper<RoomUserRelation> roomUserRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
                roomUserRelationLambdaQueryWrapper.eq(RoomUserRelation::getRoomId, unfinishedRoom.getId());
                int count = roomUserRelationService.count(roomUserRelationLambdaQueryWrapper);
//                当完成人数等于房间人数，或者房间人数为一时，直接平分奖金
                if (count == allFinishedUserId.size() || unfinishedRoom.getSportParticipantsCount() == 1) {
                    result = perMoney;
                } else {
                    double v;
//                    房间内每个人的支付金额如果超过支付宝的服务费的阈值
                    if (perMoney > CommentUtils.ZhiFuBaoThreshold) {
                        v = unfinishedRoom.getCumulativeDeposit() * 0.994 / allFinishedUserId.size();
                    } else {
                        v = unfinishedRoom.getCumulativeDeposit() / allFinishedUserId.size();
                    }
//                    如果个人收益
                    if (perMoney > v) {
                        result = perMoney;
                    } else {
                        result = (perMoney + v) / 2;
                    }
                }
                double finalResult = result;
                allFinishedUserId.stream().forEach(userId -> {
                    if (unfinishedRoom.getPrizeType() == 1) {
                        //分钱给这些人
                        User userByUserId = userService.getUserByUserId(userId);
                        User user = new User();
                        user.setUserId(userId);
                        user.setMoney(userByUserId.getMoney() + BigDecimal.valueOf(finalResult).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
                        userService.updateById(user);
                        NewSOrder newSOrder = new NewSOrder();
                        Date nowDate = new Date();
                        newSOrder.setGmtCreate(nowDate);
                        newSOrder.setGmtModify(nowDate);
                        newSOrder.setHasPayed(1);
                        String orderNum = userByUserId.getUserId() + "-" + unfinishedRoom.getId().toString() + "-" + RandomUtil.randomString(5);
                        newSOrder.setOrderNo(orderNum);
                        newSOrder.setPayAmount(BigDecimal.valueOf(finalResult).setScale(2, BigDecimal.ROUND_DOWN));
                        Room room = roomsService.newGetById(unfinishedRoom.getId());
                        NewSportConfig sportConfig = sportConfigService.getById(room.getSportCategory());
                        newSOrder.setPayDetail("完成" + sportConfig.getName() + "押金活动室");
                        newSOrder.setRoomId(unfinishedRoom.getId());
                        newSOrder.setUserId(userByUserId.getUserId());
                        newSOrder.setUserNickName(userByUserId.getNickName());
                        newSOrder.setUserPhoneNum(userByUserId.getUserMobile());
                        newSOrder.setType(2);
                        newSOrder.setPayType(0);
                        newSOrderService.save(newSOrder);
                    }
                    Map map = new HashMap();
                    map.put("userId", userId);
                    map.put("roomId", unfinishedRoom.getId());
                    Set<Long> finishedRoomIdSet = new HashSet<>();
                    finishedRoomIdSet.add(unfinishedRoom.getId());
                    List<RoomUserRelation> allRoomMapUserByRoomId = roomUserRelationService.getAllRoomMapUserByRoomId(finishedRoomIdSet);
//                    额外判断宝箱活动室是否只有一个人完成，如果是的话，则不能领取奖励，将taken_prize设置为1
//                    if (unfinishedRoom.getPrizeType() == 2 && allRoomMapUserByRoomId.size() == 1) {
//                        roomUserRelationService.updateTakenPriceByUserIdAndRoomId(map);
//                    } else {
                    roomUserRelationService.updateAllDoneByUserIdAndRoomId(map);
//                    }
                });
//                如果是押金房间或者冒险全部完成，房间状态设置为2，否则设置为1
                if (unfinishedRoom.getPrizeType() == 1 || ((allFinishedUserId.size() == unfinishedRoomUserRelationSet.size()) && unfinishedRoom.getPrizeType() == 3)) {
                    unfinishedRoom.setFinishedFlag("2");
                     roomService.updateRoom(unfinishedRoom);
                } else {
                    unfinishedRoom.setFinishedFlag("1");
                    roomService.updateRoom(unfinishedRoom);
                }
            } else {
//                如果没有一个人完成且房间类型为
                unfinishedRoom.setFinishedFlag("2");
                roomService.updateRoom(unfinishedRoom);
            }
        });
    }

    @Scheduled(cron = "0 10 0 * * ?")
    @PostConstruct
    private void cleanPersonCreateMaxTasks() {
        log.info("清除每日用户创建最大房间数");
        Set keys = redisTemplate.keys(RedisConstants.CreateRoomMax);
        redisTemplate.delete(keys);
    }

    /**
     * 已发货奖品七天后确认收货
     */
    @Scheduled(cron = "0 10 0 * * ?")
    private void syntheticPrizeStatus() {
        Date date = new Date();//取时间
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -7);//把日期往前减少一天，若想把日期向后推一天则将负数改为正数
        date = calendar.getTime();
        Date finalDate = date;
        LambdaUpdateWrapper<SyntheticPrize> syntheticPrizeLambdaUpdateWrapper = new LambdaUpdateWrapper<SyntheticPrize>()
                .eq(SyntheticPrize::getStatus, 3)
                .and(wrapper2 -> wrapper2.lt(SyntheticPrize::getUpdateTime, finalDate))
                .and(wrapper3 -> wrapper3.eq(SyntheticPrize::getDeleted, 0))
                .set(SyntheticPrize::getStatus, 4);
        boolean update = syntheticPrizeService.update(syntheticPrizeLambdaUpdateWrapper);
        if (update) {
            log.info("成功更新已发货奖品七天后确认收货");
        } else {
            log.info("已发货奖品七天后确认收货更新失败");
        }
    }
}